﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;
using System.Windows.Input;
using Workbench.Models;
using Workbench.Shared;

namespace Workbench.Presentation
{
    public class ProcessWordsListViewModel<T> : ViewModelBase where T : WordViewModelBase
    {
        public ProcessWordsListViewModel()
        {
            CurrentWords.SubscribeItemPropChange("IsSelected", CurrentWords_IsSelectedChanged);
            this.PropertyChanged += ProcessWordsListViewModel_PropertyChanged;
            this.PageSize = 200;

            nextPageCommand = new _NextPageCommand(this);
            prevPageCommand = new _PrevPageCommand(this);
        }

        #region Event Handlers

        private void CurrentWords_IsSelectedChanged(T wordViewModel)
        {
            if (wordViewModel.IsSelected)
            {
                if (LastSelectedWord != wordViewModel)
                {
                    LastSelectedWord = wordViewModel;
                }
                selectedWords.Add(wordViewModel);
            }
            else
            {
                if (selectedWords.Contains(wordViewModel))
                {
                    selectedWords.Remove(wordViewModel);
                }
            }
        }

        void ProcessWordsListViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            switch (e.PropertyName)
            {
                case "CurrentPage": ShowCurrentPage(); break;
                case "PageSize": CurrentPage = 1; RefreshTotalPages(); break;
            }
        }

        #endregion Event Handlers

        #region Properties

        private int currentPage;
        public int CurrentPage
        {
            get { return currentPage; }
            set { currentPage = value; RaisePropertyChanged(); }
        }

        private int pageSize;
        public int PageSize
        {
            get { return pageSize; }
            set { pageSize = value; RaisePropertyChanged(); }
        }

        private int totalPages;
        public int TotalPages
        {
            get { return totalPages; }
            set { totalPages = value; RaisePropertyChanged(); }
        }


        private bool shouldHideProcessed;
        public bool ShouldHideProcessed
        {
            get { return shouldHideProcessed; }
            set { shouldHideProcessed = value; RaisePropertyChanged(); }
        }
        
        private ObservableCollection<T> currentWords = new ObservableCollection<T>();
        public ObservableCollection<T> CurrentWords { get { return currentWords; } }

        private List<T> availableWords = new List<T>();
        public List<T> AvailableWords { get { return availableWords; } }

        private T lastSelectedWord;
        public T LastSelectedWord
        {
            get { return lastSelectedWord; }
            set
            {
                if (lastSelectedWord != value)
                {
                    lastSelectedWord = value;
                    RaiseThrottledPropertyChanged(200);
                }
            }
        }

        private ObservableCollection<T> selectedWords = new ObservableCollection<T>();
        public ObservableCollection<T> SelectedWords { get { return selectedWords; } }
       
        #endregion Properties

        #region Commands

        #region NextPageCommand

        readonly _NextPageCommand nextPageCommand;
        public ICommand NextPageCommand
        {
            get { return nextPageCommand; }
        }

        private class _NextPageCommand : ICommand
        {
            readonly ProcessWordsListViewModel<T> viewModel;

            public _NextPageCommand(ProcessWordsListViewModel<T> viewModel)
            {
                this.viewModel = viewModel;
                viewModel.PropertyChanged += viewModel_PropertyChanged;
            }

            void viewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
            {
                if (string.Compare(e.PropertyName, "CurrentPage", false) == 0
                 || string.Compare(e.PropertyName, "TotalPages", false) == 0)
                {
                    RaiseCanExecuteChanged();
                }
            }

            public bool CanExecute(object parameter)
            {
                return viewModel.TotalPages > 0 && viewModel.CurrentPage + 1 <= viewModel.TotalPages;
            }

            public void RaiseCanExecuteChanged()
            {
                this.CanExecuteChanged(null, EventArgs.Empty);
            }

            public void Execute(object parameter)
            {
                viewModel.CurrentPage++;
            }

            public event EventHandler CanExecuteChanged = (sender, args) => { };
        }

        #endregion NextPageCommand

        #region PrevPageCommand

        readonly _PrevPageCommand prevPageCommand;
        public ICommand PrevPageCommand
        {
            get { return prevPageCommand; }
        }

        private class _PrevPageCommand : ICommand
        {
            readonly ProcessWordsListViewModel<T> viewModel;

            public _PrevPageCommand(ProcessWordsListViewModel<T> viewModel)
            {
                this.viewModel = viewModel;
                viewModel.PropertyChanged += viewModel_PropertyChanged;
            }

            void viewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
            {
                if (string.Compare(e.PropertyName, "CurrentPage", false) == 0
                 || string.Compare(e.PropertyName, "TotalPages", false) == 0)
                {
                    RaiseCanExecuteChanged();
                }
            }

            public bool CanExecute(object parameter)
            {
                return viewModel.TotalPages > 0 && viewModel.CurrentPage - 1 > 0;
            }

            public void RaiseCanExecuteChanged()
            {
                this.CanExecuteChanged(null, EventArgs.Empty);
            }

            public void Execute(object parameter)
            {
                viewModel.CurrentPage--;
            }

            public event EventHandler CanExecuteChanged = (sender, args) => { };
        }

        #endregion NextPageCommand

        #endregion

        #region Actions

        public void ShowCurrentPage()
        {
            LastSelectedWord = null;
            SelectedWords.Clear();
            CurrentWords.Clear();
            CurrentWords.AddRange(availableWords.Skip((CurrentPage - 1) * PageSize).Take(PageSize));
        }

        public void RefreshTotalPages()
        {
            TotalPages = (int)Math.Ceiling(AvailableWords.Count / (double)PageSize);
            if (CurrentPage > TotalPages)
            {
                CurrentPage = TotalPages;
            }
        }

        public void ShowWords(IOrderedEnumerable<T> wordViewModels)
        {
            Unload();
            AvailableWords.AddRange(wordViewModels);
            CurrentPage = 1;
            RefreshTotalPages();
        }

        public void Unload()
        {
            this.AvailableWords.Clear();
            this.CurrentPage = 0;
            this.CurrentWords.Clear();
            this.LastSelectedWord = null;
            this.SelectedWords.Clear();
            this.TotalPages = 0;
        }

        #endregion
    }
}
